GHashTable *running_apps;
GHashTable *visible_id_to_app;
GHashTable *id_to_app;
+ GHashTable *startup_wm_class_to_app;
GSList *known_vendor_prefixes;
};
/* All the objects in this hash table are owned by id_to_app */
priv->visible_id_to_app = g_hash_table_new (g_str_hash, g_str_equal);
+ priv->startup_wm_class_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL,
+ (GDestroyNotify)g_object_unref);
+
/* We want to track NoDisplay apps, so we add INCLUDE_NODISPLAY. We'll
* filter NoDisplay apps out when showing them to the user. */
priv->apps_tree = gmenu_tree_new ("applications.menu", GMENU_TREE_FLAGS_INCLUDE_NODISPLAY);
g_hash_table_destroy (priv->running_apps);
g_hash_table_destroy (priv->id_to_app);
g_hash_table_destroy (priv->visible_id_to_app);
+ g_hash_table_destroy (priv->startup_wm_class_to_app);
g_slist_free_full (priv->known_vendor_prefixes, g_free);
priv->known_vendor_prefixes = NULL;
GMenuTreeEntry *old_entry;
char *prefix;
ShellApp *app;
-
+ GDesktopAppInfo *info;
+ const char *startup_wm_class;
+
prefix = get_prefix_for_entry (entry);
-
+
if (prefix != NULL
&& !g_slist_find_custom (self->priv->known_vendor_prefixes, prefix,
(GCompareFunc)g_strcmp0))
prefix);
else
g_free (prefix);
-
+
app = g_hash_table_lookup (self->priv->id_to_app, id);
if (app != NULL)
{
if (!gmenu_tree_entry_get_is_nodisplay_recurse (entry))
g_hash_table_replace (self->priv->visible_id_to_app, (char*)id, app);
+ if (old_entry)
+ {
+ GDesktopAppInfo *old_info;
+ const gchar *old_startup_wm_class;
+
+ old_info = gmenu_tree_entry_get_app_info (old_entry);
+ old_startup_wm_class = g_desktop_app_info_get_startup_wm_class (old_info);
+
+ if (old_startup_wm_class)
+ g_hash_table_remove (self->priv->startup_wm_class_to_app, old_startup_wm_class);
+ }
+
+ info = gmenu_tree_entry_get_app_info (entry);
+ startup_wm_class = g_desktop_app_info_get_startup_wm_class (info);
+ if (startup_wm_class)
+ g_hash_table_replace (self->priv->startup_wm_class_to_app,
+ (char*)startup_wm_class, g_object_ref (app));
+
if (old_entry)
gmenu_tree_item_unref (old_entry);
}
}
/**
- * shell_app_system_lookup_wmclass:
+ * shell_app_system_lookup_desktop_wmclass:
* @system: a #ShellAppSystem
* @wmclass: A WM_CLASS value
*
- * Find a valid application corresponding to a WM_CLASS value.
+ * Find a valid application whose .desktop file, without the extension
+ * and properly canonicalized, matches @wmclass.
*
* Returns: (transfer none): A #ShellApp for @wmclass
*/
ShellApp *
-shell_app_system_lookup_wmclass (ShellAppSystem *system,
- const char *wmclass)
+shell_app_system_lookup_desktop_wmclass (ShellAppSystem *system,
+ const char *wmclass)
{
char *canonicalized;
char *desktop_file;
return app;
}
+/**
+ * shell_app_system_lookup_startup_wmclass:
+ * @system: a #ShellAppSystem
+ * @wmclass: A WM_CLASS value
+ *
+ * Find a valid application whose .desktop file contains a
+ * StartupWMClass entry matching @wmclass.
+ *
+ * Returns: (transfer none): A #ShellApp for @wmclass
+ */
+ShellApp *
+shell_app_system_lookup_startup_wmclass (ShellAppSystem *system,
+ const char *wmclass)
+{
+ return g_hash_table_lookup (system->priv->startup_wm_class_to_app, wmclass);
+}
+
void
_shell_app_system_notify_app_state_changed (ShellAppSystem *self,
ShellApp *app)
return TRUE;
}
+/**
+ * get_app_from_window_wmclass:
+ *
+ * Looks only at the given window, and attempts to determine
+ * an application based on WM_CLASS. If one can't be determined,
+ * return %NULL.
+ *
+ * Return value: (transfer full): A newly-referenced #ShellApp, or %NULL
+ */
+static ShellApp *
+get_app_from_window_wmclass (MetaWindow *window)
+{
+ ShellApp *app;
+ ShellAppSystem *appsys;
+ char *appid;
+ const char *wm_class;
+ const char *wm_instance;
+ char *with_desktop;
+
+ appsys = shell_app_system_get_default ();
+
+ /* Notes on the heuristics used here:
+ much of the complexity here comes from the desire to support
+ Chrome apps.
+
+ From https://bugzilla.gnome.org/show_bug.cgi?id=673657#c13
+
+ Currently chrome sets WM_CLASS as follows (the first string is the 'instance',
+ the second one is the 'class':
+
+ For the normal browser:
+ WM_CLASS(STRING) = "chromium", "Chromium"
+
+ For a bookmarked page (through 'Tools -> Create application shortcuts')
+ WM_CLASS(STRING) = "wiki.gnome.org__GnomeShell_ApplicationBased", "Chromium"
+
+ For an application from the chrome store (with a .desktop file created through
+ right click, "Create shortcuts" from Chrome's apps overview)
+ WM_CLASS(STRING) = "crx_blpcfgokakmgnkcojhhkbfbldkacnbeo", "Chromium"
+
+ The .desktop file has a matching StartupWMClass, but the name differs, e.g. for
+ the store app (youtube) there is
+
+ .local/share/applications/chrome-blpcfgokakmgnkcojhhkbfbldkacnbeo-Default.desktop
+
+ with
+
+ StartupWMClass=crx_blpcfgokakmgnkcojhhkbfbldkacnbeo
+ */
+
+ /* first try a match from WM_CLASS to StartupWMClass */
+ wm_class = meta_window_get_wm_class (window);
+ app = shell_app_system_lookup_startup_wmclass (appsys, wm_class);
+ if (app != NULL)
+ return g_object_ref (app);
+
+ /* then try a match from WM_CLASS (instance part) to StartupWMClass */
+ wm_instance = meta_window_get_wm_class_instance (window);
+ app = shell_app_system_lookup_startup_wmclass (appsys, wm_instance);
+ if (app != NULL)
+ return g_object_ref (app);
+
+ /* then try a match from WM_CLASS to .desktop */
+ app = shell_app_system_lookup_desktop_wmclass (appsys, wm_class);
+ if (app != NULL)
+ return g_object_ref (app);
+
+ /* finally, try a match from WM_CLASS (instance part) to .desktop
+ (unlikely to find anything at this point, but still worth a try) */
+ app = shell_app_system_lookup_desktop_wmclass (appsys, wm_instance);
+ if (app != NULL)
+ return g_object_ref (app);
+
+ return NULL;
+}
+
/**
* get_app_from_window_group:
* @monitor: a #ShellWindowTracker
/* Check if the app's WM_CLASS specifies an app; this is
* canonical if it does.
*/
- result = shell_app_system_lookup_wmclass (app_system,
- meta_window_get_wm_class (window));
+ result = get_app_from_window_wmclass (window);
if (result != NULL)
return g_object_ref (result);